package com.cherrypt.api.core.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.baomidou.mybatisplus.extension.toolkit.SqlHelper;
import com.cherrypt.api.common.enums.ResultEnum;
import com.cherrypt.api.common.enums.UserInfoEnum;
import com.cherrypt.api.common.exception.TipException;
import com.cherrypt.api.core.dao.UserInfoDao;
import com.cherrypt.api.core.service.UserLoginService;
import com.cherrypt.api.model.dataobject.UserInfo;
import com.cherrypt.api.core.service.UserInfoService;
import com.cherrypt.api.common.util.CheckUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.stereotype.Service;

import java.time.Duration;

/**
 * @author intent
 * @date 2019/7/14 16:39
 * @about <link href='http://zzyitj.xyz/'/>
 */
@Service
public class UserInfoServiceImpl extends ServiceImpl<UserInfoDao, UserInfo> implements UserInfoService {
    private static final Logger logger = LoggerFactory.getLogger(UserInfoServiceImpl.class);

    @Autowired
    private StringRedisTemplate redisTemplate;

    @Autowired
    private ValueOperations<String, Object> valueOperations;

    @Value("${api.config.redis.userInfo.prefix}")
    private String userInfoPrefix;

    @Value("${api.config.redis.userInfo.exp}")
    private long userInfoExp;

    @Value("${api.config.userInfo.initUpload}")
    private long userInitUpload;

    @Autowired
    private UserLoginService userLoginService;

    @Override
    public boolean saveUserInfo(UserInfo userInfo) {
        userInfo.setUploaded(userInitUpload);
        return SqlHelper.retBool(this.baseMapper.insertUserInfo(userInfo));
    }

    @Override
    public UserInfo getRedisUserInfoByUid(int uid) {
        return (UserInfo) valueOperations.get(userInfoPrefix + uid);
    }

    @Override
    public void saveRedisUserInfo(UserInfo userInfo) {
        valueOperations.set(userInfoPrefix + userInfo.getUid(), userInfo, Duration.ofSeconds(userInfoExp));
    }

    @Override
    public boolean removeRedisUserInfo(int uid) {
        Boolean delete = redisTemplate.delete(userInfoPrefix + uid);
        if (delete != null) {
            return delete;
        }
        return false;
    }

    @Override
    public UserInfo getUserInfoByUid(int uid) throws TipException {
        // 先从Redis中查询
        UserInfo userInfo = getRedisUserInfoByUid(uid);
        // Redis中没有只有从数据库中查询
        if (userInfo == null) {
            userInfo = this.baseMapper.selectUserInfoByUid(uid);
            // 把userInfo存储在redis中
            if (userInfo == null) {
                throw new TipException(ResultEnum.USER_EMPTY_ERROR);
            }
            if (userInfo.getStatus() == UserInfoEnum.BAN.getCode()) {
                throw new TipException(ResultEnum.ACCOUNT_BAN_ERROR);
            }
            saveRedisUserInfo(userInfo);
            logger.info("缓存UserInfo到Redis: {}", userInfo);
        }
        return userInfo;
    }

    @Override
    public UserInfo getFriendByUid(int uid) {
        return this.baseMapper.selectFriendById(uid);
    }

    @Override
    public UserInfo getUserByUsername(String username) throws TipException {
        if (StringUtils.isNotBlank(username)) {
            CheckUtils.checkUsername(username);
        }
        return getOne(new QueryWrapper<UserInfo>().eq("username", username));
    }

    @Override
    public UserInfo getUserInfoByPasskey(String passkey) throws TipException {
        if (StringUtils.isBlank(passkey)) {
            throw new TipException(ResultEnum.PASSKEY_EMPTY_ERROR);
        }
        return getOne(new QueryWrapper<UserInfo>().eq("passkey", passkey));
    }

    @Override
    public boolean updateUserInfoByUid(UserInfo userInfo) {
        boolean isUpdate = this.update(userInfo, new UpdateWrapper<UserInfo>()
                .eq("uid", userInfo.getUid()));
        // 删除数据库缓存
        if (isUpdate) {
            removeRedisUserInfo(userInfo.getUid());
        }
        return isUpdate;
    }

    @Override
    public boolean updateUDByUid(int uid, long upload, long download) {
        boolean isUpdate = this.update(new UpdateWrapper<UserInfo>()
                .setSql("uploaded = uploaded + " + upload)
                .setSql("downloaded = downloaded + " + download)
                .eq("uid", uid));
        if (isUpdate) {
            removeRedisUserInfo(uid);
        }
        return isUpdate;
    }

    @Override
    public boolean updateExpByUid(int uid, long exp) {
        // 删除数据库缓存
        if (this.update(new UpdateWrapper<UserInfo>()
                .setSql("exp = exp + " + exp)
                .eq("uid", uid))) {
            removeRedisUserInfo(uid);
        }
        return false;
    }

    /**
     * 同时update UserLogin和UserInfo表的状态
     *
     * @param uid
     * @param userInfoEnum
     * @return
     */
    @Override
    public boolean updateStatusByUid(int uid, UserInfoEnum userInfoEnum) {
        if (userLoginService.updateStatusByUid(uid, userInfoEnum.getCode())) {
            UserInfo userInfo = new UserInfo();
            userInfo.setUid(uid);
            userInfo.setStatus(userInfoEnum.getCode());
            if (updateUserInfoByUid(userInfo)) {
                return removeRedisUserInfo(uid);
            } else {
                return false;
            }
        }
        return false;
    }
}
